<?php
namespace app\controller;
use think\facade\Db;
//抢购商品demo
/*

CREATE TABLE `buy` (
  `buy_id` int(11) NOT NULL,
  `user_id` int(11) NOT NULL,
  `buy_name` varchar(255) NOT NULL,
  `buy_time` datetime NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- --------------------------------------------------------

--
-- 表的结构 `shop`
--

CREATE TABLE `shop` (
  `shop_id` int(11) NOT NULL,
  `shop_name` varchar(255) NOT NULL,
  `shop_num` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

--
-- 转存表中的数据 `shop`
--

INSERT INTO `shop` (`shop_id`, `shop_name`, `shop_num`) VALUES
(1, '鞋子', 10),
(2, '衣服', 12);

--
-- 转储表的索引
--

--
-- 表的索引 `buy`
--
ALTER TABLE `buy`
  ADD PRIMARY KEY (`buy_id`);

--
-- 表的索引 `shop`
--
ALTER TABLE `shop`
  ADD PRIMARY KEY (`shop_id`);

--
-- 在导出的表使用AUTO_INCREMENT
--

--
-- 使用表AUTO_INCREMENT `buy`
--
ALTER TABLE `buy`
  MODIFY `buy_id` int(11) NOT NULL AUTO_INCREMENT;

--
-- 使用表AUTO_INCREMENT `shop`
--
ALTER TABLE `shop`
  MODIFY `shop_id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=3;
COMMIT;

*/



class ShopBuyTest{
    //使用文件锁
    public function index2(){
        $txt=__DIR__.'/test.txt';
        $file = fopen($txt,"w+");
        if (flock($file,LOCK_EX)){
            fwrite($file,"Write something");
            $shop = Db::table('shop')->where('shop_id',1)->find();
            if($shop['shop_num']>0){
                 Db::table('shop')->where('shop_id',1)->dec('shop_num')->update();
                 $buy_data = [
                    'buy_name'=>$shop['shop_name'],
                    'buy_time'=>date("Y-m-d H:i:s")
                ];
                 Db::table('buy')->insert($buy_data);
            }else{
                echo "买完了";
            }            
        } else {
            fwrite($file,"Error locking file!");
            // echo "Error locking file!";
        }
        fclose($file);            
    }
    //使用悲观锁
    public function index3(){
        try {
            Db::startTrans();  // 开始事务
        
            $shop = Db::table('shop')->lock(true)->where('shop_id', 1)->find();
            
            if ($shop['shop_num'] > 0) {
                Db::table('shop')->where('shop_id', 1)->dec('shop_num')->update();
                $buy_data = [
                    'buy_name' => $shop['shop_name'],
                    'buy_time' => date("Y-m-d H:i:s")
                ];
                Db::table('buy')->insert($buy_data);
        
                Db::commit();  // 提交事务
            } else {
                echo "买完了";
                Db::rollback();  // 回滚事务
            }
        } catch (\Exception $e) {
            Db::rollback();  // 出现异常时回滚事务
            // 处理异常
        }        
    }
    //使用redis+lua
    public function index($shop_id = 1){
        $script = "
        -- 取用户key
        local people_key = KEYS[1]
        -- 取库存量
        local shop_num = tonumber(ARGV[1])
        -- 取获得奖品用户数量（使用set集合， 当集合 people_key 不存在时，返回 0）
        local current_people_num = redis.call('scard', people_key)
        -- 如果奖品数量没有抢购完
        if current_people_num < shop_num then
            local user_id = ARGV[2]
            -- 直接将用户添加到购买集合中
           local add =  redis.call('sadd', people_key, user_id)
           if add == 1  then
                -- 返回包含状态和用户ID的 JSON 字符串
                return cjson.encode({status=200, user_id=user_id, message='ok'})
            else
                return cjson.encode({status=500, user_id='', message='unique'})
            end
        else
            -- 库存不足，返回标识
            return cjson.encode({status=500, user_id='', message='sold_out'})
        end
        ";
        $redis = new \think\cache\driver\Redis();
        $redis_connect = $redis->connect("127.0.0.1", 6379);
        if(!$redis_connect){return json(['status'=>500,'msg'=>'redis连接失败']);}
        $shop_data_key = 'shop_data'.$shop_id; 
        $shop = $redis->get($shop_data_key);
        if(empty($shop)){
            $shop = Db::table('shop')->where('shop_id', $shop_id)->find();
            $redis->set($shop_data_key,json_encode($shop));
        }else{
            $shop = json_decode($shop,true);   
        }
        
        $people_key = 'shop_data_people_id'.$shop_id;
        $sha = $redis->script('load', $script);
        $result = $redis->evalSha($sha,[$people_key, strval($shop['shop_num']), strval(rand(1, 20))],1);
        if ($result === false) {
            echo "执行 Lua 脚本时出错：" . $redis->getLastError();
        } else {
            dump($result);
            $res = json_decode($result,true);
            // 继续你的逻辑
            if($res['status'] == 200){
                $user_data = [
                    'user_id'=>$res['user_id'],
                    'buy_name'=>$shop['shop_name'],
                    'buy_time'=>date("Y-m-d H:i:s")
                ];
                Db::table('buy')->insert($user_data);
            }else{
                 dump($redis->SMEMBERS($people_key)); 
                 dump( Db::table('buy')->select()->toArray());
            }
            
        }        
        $redis->close();
    }
     public function selctIndex($shop_id = 1){
        $redis = new \think\cache\driver\Redis();
        $redis->connect("127.0.0.1", 6379);
        $shop_data_key = 'shop_data'.$shop_id; 
        $shop = json_decode($shop = $redis->get($shop_data_key),true); 
        dump($shop);
        $people_key = 'shop_data_people_id'.$shop_id;
         $a =  $redis->SMEMBERS($people_key);        
         dump($a);
         dump($redis->scard($people_key));
         $redis->delete($people_key);
         $redis->delete($shop_data_key);
         Db::table('buy')->delete(true);
         $redis->close();
     }
}
?>